package hyl.core.struct;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import hyl.core.run.IDo1;
import hyl.core.run.MyRun;

/**
 * 我想构造一个类似于window 底层的消息框架 只用于当前java程序环境
 * 
 * 消息被监听的组件使用后,继续向后抛送(层层消费)
 * 
 * 
 * 
 * @author 37798955@qq.com
 *
 */
public class MsgManager<K, V> {
	// 内核级消息
	public static final int M消息_BIO = 0;
	// 消息队列
	final ArrayBlockingQueue<Msg<K, V>> queue = new ArrayBlockingQueue<>(1000);
	// 消费队列
	final ConcurrentHashMap<K, Set<IDo1<Msg<K, V>>>> listeners = new ConcurrentHashMap<>();

	static final int mainThreadnum = 2;
	// 双主线程,加快处理速度
	MyRun _mpool;

	public MsgManager(String 事件类型) {
		_mpool = MyRun.getInstance(事件类型, mainThreadnum);
		for (int i = 0; i < mainThreadnum; i++) {
			_mpool.execute(new 消息监听者());
		}
	}

	// 默认的 内核级事件
	static MsgManager<String, Object> AppMsgManager = new MsgManager<String, Object>("HYL.CORE");

	public static MsgManager<String, Object> get单例() {
		return AppMsgManager;
	}
	// 自定义 事件管理者
	// public static <K, V> MsgManager<K, V> get单例(String 事件类型) {
	// return new MsgManager<K, V> (事件类型);
	// }

	public void close() {
		_mpool.close();
	}

	// private Lock lock = new ReentrantLock();
	public synchronized void do注册(K event, IDo1<Msg<K, V>> handle) {
		Set<IDo1<Msg<K, V>>> handlelist = listeners.get(event);
		if (handlelist == null)
			handlelist = new HashSet<>();
		handlelist.add(handle);
		listeners.put(event, handlelist);
	}

	public void do写入消息(K 事件, V 参数) {
		Msg<K, V> 元素 = new Msg<K, V>();
		元素.key = 事件;
		元素.value = 参数;
		do写入消息(元素);
	}

	public void do写入消息(Msg<K, V> 元素) {
		try {
			if (元素 != null)
				queue.put(元素);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	class 消息监听者 implements Runnable {
		@Override
		public void run() {
			while (true) {
				try {

					Msg<K, V> tde = queue.take();
					// 每个消息有独立的线程跟进
					new Thread(() -> do通知(tde)).start();

				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}

		/**
		 * 先注册后消费, 否则事件被丢弃
		 * 
		 * @param key
		 * @param obj
		 */
		synchronized void do通知(Msg<K, V> obj) {
			// 列出所有监听者
			Set<IDo1<Msg<K, V>>> setev = listeners.get(obj.key);
			if (setev == null)
				return;
			for (IDo1<Msg<K, V>> handle : setev) {
				// 每个监听者调用这个对象
				handle.run(obj);
			}
		}
	}

}
